package com.shy.base.util;


import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CacheUtil {

	/**
     * 为了不引入第三方的依赖，直接使用 map， LocalDateTime 的值为过期时间
     */
    private static final Map<String, Map<Object, LocalDateTime>> MAP_CACHE = new ConcurrentHashMap<>(16);

    /**
     * 线程池
     */
    private static final ScheduledExecutorService executorService;

    /**
     * 前缀
     */
    private static final String THREAD_POOL_NAME_PREFIX = "delete_expire_cache_";

    static {
        executorService = new ScheduledThreadPoolExecutor(1,
                ThreadFactoryBuilder.create()
                        .setNamePrefix(THREAD_POOL_NAME_PREFIX)
                        .build());
    }

    /**
     * 设置缓存
     *
     * @param key        键
     * @param value      值
     * @param expireDate 过期时间
     */
    public static <T> void set(String key, T value, LocalDateTime expireDate) {
        // 新增缓存
        Map<Object, LocalDateTime> valueMap = new HashMap<>(2);
        // 设置
        valueMap.put(value, expireDate);
        // 缓存
        MAP_CACHE.put(key, valueMap);
    }

    /**
     * 设置缓存
     *
     * @param key 键
     * @param <T> 值的类型
     */
    @SuppressWarnings("unchecked")
	public static <T> T get(String key) {
        // 缓存
        Map<Object, LocalDateTime> timeMap = MAP_CACHE.get(key);
        if (MapUtil.isEmpty(timeMap)) {
            // 没有值则删除, 解决并发问题
            MAP_CACHE.remove(key);
            return null;
        }
        for (Object value : timeMap.keySet()) {
            return (T) value;
        }
        return null;
    }

    /**
     * 假如过期则删除
     *
     * @param key 键
     */
    public static void deleteIfExpire(String key) {
        Map<Object, LocalDateTime> timeMap = MAP_CACHE.get(key);
        if (MapUtil.isEmpty(timeMap)) {
            MAP_CACHE.remove(key);
            return;
        }
        Iterator<Map.Entry<Object, LocalDateTime>> it = timeMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Object, LocalDateTime> entry = it.next();
            if (entry == null || entry.getValue() == null) {
                continue;
            }
            LocalDateTime localDateTime = entry.getValue();
            if (localDateTime.isAfter(LocalDateTime.now())) {
                continue;
            }
            // 假如过期则删除
            timeMap.remove(entry.getKey());
        }
        // 假如为空，则删除
        if (MapUtil.isEmpty(timeMap)) {
            MAP_CACHE.remove(key);
        }
    }

    /**
     * 清理所有缓存
     */
    public static void clearAll() {
        MAP_CACHE.clear();
    }

    /**
     * 删除过期缓存，只要在项目启动时调用一次
     */
    public static void clearExpireCache() {
        // 使用调度线程池，每秒执行一次
        executorService.scheduleWithFixedDelay(() -> {
            try {
                Map<String, Map<Object, LocalDateTime>> mapCache = CacheUtil.MAP_CACHE;
                if (MapUtil.isEmpty(mapCache)) {
                    return;
                }
                for (Map.Entry<String, Map<Object, LocalDateTime>> entry : mapCache.entrySet()) {
                    Map<Object, LocalDateTime> timeMap = entry.getValue();
                    if (MapUtil.isEmpty(timeMap) || StrUtil.isBlankIfStr(entry.getKey())) {
                        continue;
                    }
                    CacheUtil.deleteIfExpire(entry.getKey());
                }
            } catch (Exception exception) {
                log.error("清理过期缓存异常", exception);
            }
        }, 0, 1, TimeUnit.SECONDS);
    }

}
